package com.yxy.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.yxy.common.PageResult;
import com.yxy.constant.MessageConstant;
import com.yxy.constant.StatusConstant;
import com.yxy.exception.UseWarningException;
import com.yxy.mapper.SightsBookingMapper;
import com.yxy.mapper.SightsMapper;
import com.yxy.mapper.UserMapper;
import com.yxy.pojo.dto.SightsBookingDTO;
import com.yxy.pojo.dto.SightsBookingPageQueryDTO;
import com.yxy.pojo.entity.BookingPerson;
import com.yxy.pojo.entity.Sights;
import com.yxy.pojo.entity.SightsBooking;
import com.yxy.pojo.entity.User;
import com.yxy.pojo.vo.SightsBookingPageQueryVO;
import com.yxy.pojo.vo.SightsBookingVO;
import com.yxy.service.SightsBookingService;
import com.yxy.utils.ExcelUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;

@Slf4j
@Service
public class SightsBookingServiceImpl implements SightsBookingService {

    @Autowired
    private SightsBookingMapper sightsBookingMapper;
    @Autowired
    private SightsMapper sightsMapper;
    @Autowired
    private UserMapper userMapper;

    /**
     * 添加景点预约
     *
     * @param sightsBookingDTO
     */
    @Transactional
    @Override
    public void addSightsBooking(SightsBookingDTO sightsBookingDTO) {
        // 查询景点信息，计算价格
        Sights sights = sightsMapper.selectById(sightsBookingDTO.getSightsId());
        BigDecimal totalPrice = sights.getPrice().multiply(new BigDecimal(sightsBookingDTO.getBookingPersonList().size()));
        // 先添加到景点预约表，然后返回预约id
        SightsBooking sightsBooking = SightsBooking.builder()
                .sightsId(sightsBookingDTO.getSightsId())
                .userId(sightsBookingDTO.getUserId())
                .bookingTime(sightsBookingDTO.getBookingTime().plusDays(1))
                .number(sightsBookingDTO.getBookingPersonList().size())
                .price(totalPrice)
                .status(StatusConstant.BOOKING_OK)
                .build();
        sightsBookingMapper.add(sightsBooking);

        // 再添加到预约人员表
        sightsBookingDTO.getBookingPersonList().forEach(bookingPerson -> {
            sightsBookingMapper.addBookingPerson(BookingPerson.builder()
                    .bookingId(sightsBooking.getId())
                    .name(bookingPerson.getName())
                    .phone(bookingPerson.getPhone())
                    .idCard(bookingPerson.getIdCard())
                    .build());
        });
    }

    /**
     * 获取景点预约信息（判断是否过期）
     * 因为每个用户每个景点都只能预约一次，在这次预约未结束（status==1）的情况下不存在其他状态，除非本次预约取消或者已过期或已使用
     * 所以获取的列表里面最后一个就是最新的记录（称为本次记录）
     * 若本次记录为null，则表示用户在本景点一次预约记录也没有，则直接返回状态为0
     * 若本次记录状态为1，在预定的时间之前未使用（status!=2 或 status==1）,则超过时间后被视为过期 状态记为-1
     *
     * @param sightsId
     * @param userId
     * @return
     */
    @Override
    public SightsBookingVO getSightsBooking(Integer sightsId, Integer userId) {
        List<SightsBooking> voList = sightsBookingMapper.selectBySightsIdAndUserId(sightsId, userId);
        SightsBookingVO vo = new SightsBookingVO();
        if (voList.isEmpty()) {
            vo.setStatus(StatusConstant.BOOKING_CANCEL);
            return vo;
        }
        SightsBooking sightsBooking = voList.get(voList.size() - 1);
        // 判断是否过期
        if (sightsBooking.getStatus() == StatusConstant.BOOKING_OK && sightsBooking.getBookingTime().isBefore(LocalDate.now())) {
            // 过期
            sightsBookingMapper.updateStatus(SightsBooking.builder()
                    .id(sightsBooking.getId())
                    .sightsId(sightsBooking.getSightsId())
                    .userId(sightsBooking.getUserId())
                    .status(StatusConstant.BOOKING_EXPIRED)
                    .build());
            vo.setStatus(StatusConstant.BOOKING_EXPIRED);
            return vo;
        }
        BeanUtils.copyProperties(sightsBooking, vo);
        return vo;
    }

    /**
     * 取消景点预约
     *
     * @param sightsId
     * @param userId
     */
    @Transactional
    @Override
    public void cancelSightsBooking(Integer sightsId, Integer userId, Integer bookingId) {
        // 修改警员预约表中的状态
        SightsBooking sightsBooking = SightsBooking.builder()
                .id(bookingId)
                .userId(userId)
                .sightsId(sightsId)
                .status(StatusConstant.BOOKING_CANCEL)
                .build();
        sightsBookingMapper.updateStatus(sightsBooking);
    }

    /**
     * 分页查询（管理端）
     * @param sightsBookingPageQueryDTO
     * @return
     */
    @Override
    public PageResult page(SightsBookingPageQueryDTO sightsBookingPageQueryDTO) {
        PageHelper.startPage(sightsBookingPageQueryDTO.getPage(), sightsBookingPageQueryDTO.getPageSize());
        Page<SightsBookingPageQueryVO> page = sightsBookingMapper.pageQuery(sightsBookingPageQueryDTO);
        page.forEach(item -> {
            // 查询每个景点的封面
            Sights sights = sightsMapper.selectById(item.getSightsId());
            item.setCover(sights.getCover());
            // 景点名
            item.setSightsName(sights.getName());
            // 查询预约人的信息列表
            List<BookingPerson> bookingPersonList = sightsBookingMapper.selectBookingPersonListBySightsBookingId(item.getId());
            item.setBookingPersonList(bookingPersonList);
            // 判断是否过期
            if (item.getStatus() == StatusConstant.BOOKING_OK && item.getBookingTime().isBefore(LocalDate.now())) {
                // 过期
                sightsBookingMapper.updateStatus(SightsBooking.builder()
                        .id(item.getId())
                        .sightsId(item.getSightsId())
                        .userId(item.getUserId())
                        .status(StatusConstant.BOOKING_EXPIRED)
                        .build());
                item.setStatus(StatusConstant.BOOKING_EXPIRED);
            }
        });
        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 分页查询用户景点预定（用户端）
     * @param sightsBookingPageQueryDTO
     * @return
     */
    @Override
    public PageResult pageQuerySightsBooking(SightsBookingPageQueryDTO sightsBookingPageQueryDTO) {
        PageHelper.startPage(sightsBookingPageQueryDTO.getPage(), sightsBookingPageQueryDTO.getPageSize());
        Page<SightsBookingPageQueryVO> page = sightsBookingMapper.pageQuerySightsBooking(sightsBookingPageQueryDTO);
        page.getResult().forEach(item -> {
            // 查询景点信息
            Sights sights = sightsMapper.selectById(item.getSightsId());
            item.setSightsName(sights.getName());
            // 判断是否过期
            if (item.getStatus() == StatusConstant.BOOKING_OK && item.getBookingTime().isBefore(LocalDate.now())) {
                // 过期
                sightsBookingMapper.updateStatus(SightsBooking.builder()
                        .id(item.getId())
                        .sightsId(item.getSightsId())
                        .userId(item.getUserId())
                        .status(StatusConstant.BOOKING_EXPIRED)
                        .build());
                item.setStatus(StatusConstant.BOOKING_EXPIRED);
            }
        });
        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 根据id查询
     * @param id
     * @return
     */
    @Override
    public SightsBookingVO getSightsBookingById(Integer id) {
        SightsBooking sightsBooking = sightsBookingMapper.selectById(id);
        SightsBookingVO vo = new SightsBookingVO();
        BeanUtils.copyProperties(sightsBooking, vo);
        // 查询景点信息
        Sights sights = sightsMapper.selectById(sightsBooking.getSightsId());
        vo.setSightsName(sights.getName());
        vo.setCover(sights.getCover());
        // 发起人信息
        User user = userMapper.selectById(sightsBooking.getUserId());
        vo.setName(user.getName());
        // 查询预约人员信息
        List<BookingPerson> bookingPeople = sightsBookingMapper.selectBookingPersonListBySightsBookingId(id);
        vo.setBookingPersonList(bookingPeople);
        return vo;
    }

    /**
     * 使用
     * @param id
     */
    @Transactional
    @Override
    public String use(int id) {
        // 判断状态
        SightsBooking sightsBooking = sightsBookingMapper.selectById(id);
        // 状态错误
        if (sightsBooking.getStatus() != StatusConstant.BOOKING_OK && sightsBooking.getStatus() != StatusConstant.BOOKING_USER) {
            return StatusConstant.BOOKING_USE_ERROR;
        }
        // 预约已使用
        if (sightsBooking.getStatus() == StatusConstant.BOOKING_USER) {
            return StatusConstant.BOOKING_USE_WARNING;
        }

        sightsBookingMapper.update(SightsBooking.builder()
                .id(id)
                .useTime(LocalDate.now())
                .status(StatusConstant.BOOKING_USER)
                .build());
        // 使景点售出量加1
        Sights sights = sightsMapper.selectById(sightsBooking.getSightsId());
        sightsMapper.addSold(sights.getId(), sights.getSold() + 1);
        return StatusConstant.BOOKING_USE_OK;
    }

    /**
     * 导出到Excel
     */
    @SneakyThrows
    @Override
    public String exportToExcel() {
        // 先获取所有预定信息
        List<SightsBookingPageQueryVO> list = sightsBookingMapper.selectList();
        list.forEach(item -> {
            // 查询每个景点的封面
            Sights sights = sightsMapper.selectById(item.getSightsId());
            item.setCover(sights.getCover());
            // 景点名
            item.setSightsName(sights.getName());
            // 查询预约人的信息列表
            List<BookingPerson> bookingPersonList = sightsBookingMapper.selectBookingPersonListBySightsBookingId(item.getId());
            item.setBookingPersonList(bookingPersonList);
            // 判断是否过期
            if (item.getStatus() == StatusConstant.BOOKING_OK && item.getBookingTime().isBefore(LocalDate.now())) {
                // 过期
                sightsBookingMapper.updateStatus(SightsBooking.builder()
                        .id(item.getId())
                        .sightsId(item.getSightsId())
                        .userId(item.getUserId())
                        .status(StatusConstant.BOOKING_EXPIRED)
                        .build());
                item.setStatus(StatusConstant.BOOKING_EXPIRED);
            }
        });
        // 导出到Excel
        return ExcelUtil.exportToExcel(list, ExcelUtil.SIGHTS);
    }
}
